const fs = require("fs");
const path = require("path");
const os = require("os");
const { execSync } = require("child_process");
const fse = require("fs-extra");

module.exports = handleVue3Template;

function handleVue3Template(basePath, viewAnswer, isAll, pluginType) {
  handleAppVue(basePath, viewAnswer);
  handleComponentsIndexjs(basePath, viewAnswer);
  handleComponentDevelopmentAppVue(basePath, viewAnswer);
  handleComponentDevelopmentMockDatajs(basePath, viewAnswer);
  handleUtilHandlePlatformAdapterjs(basePath, viewAnswer);
  generateNewFiles(basePath, viewAnswer);
  deleteExtraFiles(basePath, viewAnswer);
  basePath = moveFiles(basePath, isAll, pluginType);
  return basePath;
}

function moveFiles(basePath, isAll, pluginType) {
  let pathPrefix;
  //通过本项目启动
  if (process.env["sdataPlugins"] === "true") {
    pathPrefix = path.resolve(__dirname, `../packages`);
  } else {
    pathPrefix = process.cwd();
  }
  if (isAll) {
    mkdirSync(path.resolve(pathPrefix, `${pluginType}/${basePath}`));
    fse.copySync(
      path.resolve(__dirname, `./${basePath}`),
      path.resolve(pathPrefix, `${pluginType}/${basePath}`)
    );
    mkdirSync(
      path.resolve(pathPrefix, `${pluginType}/src/utils/handlePlatform`)
    );
    fse.copySync(
      path.resolve(
        __dirname,
        `./${basePath}/src/utils/handlePlatform/adapter.js`
      ),
      path.resolve(
        pathPrefix,
        `${pluginType}/src/utils/handlePlatform/adapter.js`
      )
    );
    mkdirSync(
      path.resolve(pathPrefix, `${pluginType}/src/components/development`)
    );
    fse.copySync(
      path.resolve(
        __dirname,
        `./${basePath}/src/components/development/mockData.js`
      ),
      path.resolve(
        pathPrefix,
        `${pluginType}/src/components/development/mockData.js`
      )
    );
    fse.removeSync(path.resolve(__dirname, `./${basePath}`));
    basePath = path.resolve(pathPrefix, `${pluginType}`);
    return basePath;
  } else {
    mkdirSync(path.resolve(pathPrefix, basePath));
    fse.copySync(
      path.resolve(__dirname, `./${basePath}`),
      path.resolve(pathPrefix, basePath)
    );
    fse.removeSync(path.resolve(__dirname, `./${basePath}`));
    basePath = path.resolve(pathPrefix, basePath);
    let batchFlag = process.argv.slice(2)[0] === "--batch";
    !batchFlag && openFiles(basePath);
  }
}

function openFiles(basePath) {
  let startCommond = os.type() === "Darwin" ? "open" : "start";
  try {
    execSync(`${startCommond} ${basePath}`);
    execSync(`${startCommond} ${basePath}/src/utils/handlePlatform/adapter.js`);
    execSync(
      `${startCommond} ${basePath}/src/components/development/mockData.js`
    );
  } catch (e) {
    console.log(
      "自动打开文件失败，请手动打开，目录名：src/utils/handlePlatform/adapter.js"
    );
    console.log(
      "自动打开文件失败，请手动打开，目录名：src/components/development/mockData.js"
    );
  }
}

// src/utils/handlePlatform/adapter.js
function handleUtilHandlePlatformAdapterjs(basePath, viewAnswer) {
  const needProcess = viewAnswer.some(item => item.process);
  const templateContent = `export default function adapter(props) {
  const onlineDevelopmentMode = import.meta.env.VITE_APP_ONLINE_DEVELOPMENT_MODE;
  if (import.meta.env.PROD || (onlineDevelopmentMode && !window.online_development_islocal)) {
    /**
     *  @example
     *  props.type = (props.type === "designConfiguration" ? "designConfiguration" : "main")
     *  props.changeConfiguration && (props.changeCustomConfig = props.changeConfiguration)
     *  if (props.type === "designConfiguration") {
     *    props.customConfig = JSON.parse(props.configuration)
     *  } else {
     *    props.customConfig = props.configuration
     *  }
     *
     */
     ${
       needProcess
         ? '/**\n     * 封装smardaten触发事件的方法\n     * @param {String} eventName 事件名\n     * @param {Object} payload 事件传参\n     * @example\n     * triggerEvent("click",{value:"123"})\n     *\n     */\n    /*props.triggerEvent = function (eventName, payload = {}) {\n     props.componentId && window.eventCenter?.triggerEventNew({\n     objectId: props.appId,\n     componentId: props.componentId,\n     type: "app",\n     event: eventName,\n     //payload需为一个object\n     payload\n     )\n     }*/'
         : ""
     }
  }
  return props
}
`;
  fs.writeFileSync(
    path.resolve(
      __dirname,
      `./${basePath}/src/utils/handlePlatform/adapter.js`
    ),
    templateContent
  );
}

// src/components/development/mockData.js
function handleComponentDevelopmentMockDatajs(basePath, viewAnswer) {
  const hasDesignConfiguration = viewAnswer.some(
    item => item.viewType === "designConfiguration"
  );
  const templateContent = `import getPluginType from "@/utils/handlePlatform/getPluginType"${
    hasDesignConfiguration
      ? `\nimport { id } from '../../../pluginTemp/config.json';`
      : ""
  }

${
  hasDesignConfiguration
    ? "const pluginType = getPluginType();\nconst customConfig = JSON.parse(localStorage.getItem(`${pluginType}-secondary-${id}`))?.customConfig || {};\nexport const mockCustomConfig = customConfig;\nexport const mockChangeCustomConfig = customConfig => {\n  const mockData = JSON.parse(localStorage.getItem(`${pluginType}-secondary-${id}`)) || {};\n  mockData.customConfig = customConfig;\n  localStorage.setItem(`${pluginType}-secondary-${id}`, JSON.stringify(mockData))\n}"
    : ""
}
export const intlGetKey = i18nKey => '国际化方法-' + i18nKey;

export default {

}
  `;
  fs.writeFileSync(
    path.resolve(
      __dirname,
      `./${basePath}/src/components/development/mockData.js`
    ),
    templateContent
  );
}

// src/components/development/App.vue
function handleComponentDevelopmentAppVue(basePath, viewAnswer) {
  const hasDesignConfiguration = viewAnswer.some(
    item => item.viewType === "designConfiguration"
  );
  const importStatement = viewAnswer
    .map(item => toCamelCase(item.viewType))
    .join(",\n  ");
  const templateContent = `<script setup>
import {
  ${importStatement}
} from "@/components";${
    hasDesignConfiguration
      ? '\nimport mockData, {\n  mockCustomConfig,\n  mockChangeCustomConfig\n} from "./mockData";\nimport Utils from "@/utils";'
      : '\nimport mockData from "./mockData";'
  }

const { ${hasDesignConfiguration ? "ref, " : ""}reactive } = Vue3;
${hasDesignConfiguration ? "\nconst mainKey = ref(Utils.generateUUID());" : ""}
const renderMap = [
  ${viewAnswer
    .filter(item => item.viewType !== "designConfiguration")
    .map(item => {
      const componentName = toCamelCase(item.viewType);
      return `{ type: "${componentName}", component: ${componentName} }`;
    })
    .join(",\n  ")}
];${
    hasDesignConfiguration
      ? `\nlet customConfig = reactive(mockCustomConfig);
const showConfig = ref(false);
const changeCustomConfig = config => {
  customConfig = config;
  mainKey.value = Utils.generateUUID();
  mockChangeCustomConfig(config);
};
const toggleShrink = () => {
  showConfig.value = !showConfig.value;
};
`
      : ""
  }
const otherProps = reactive({ ...mockData${
    hasDesignConfiguration ? ", customConfig, changeCustomConfig" : ""
  } });
</script>

<template>
  <div id="development">
    <div
      id="main"
      :style="{ width: showConfig ? 'calc(100% - 300px)' : '100%' }"${
        hasDesignConfiguration ? "\n      :key='mainKey'" : ""
      }
    >${
      hasDesignConfiguration
        ? `\n      <el-button @click="toggleShrink">
        <svg
          view-box="0 0 24 24"
          :style="{
            transform: showConfig
              ? 'translate(-12px, 2px)'
              : 'translate(-24px, 2px) rotateY(180deg)',
          }"
        >
          <path d="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z"></path>
        </svg>
      </el-button>
    `
        : ""
    }
      <el-carousel trigger="click" arrow="never" :autoplay="false">
        <el-carousel-item v-for="item in renderMap" :key="item.type">
          <component :is="item.component" v-bind="otherProps" />
        </el-carousel-item>
      </el-carousel>
    </div>${
      hasDesignConfiguration
        ? `\n    <div id="configuration" :style="{ display: showConfig ? 'block' : 'none' }">
      <DesignConfiguration v-bind="otherProps" />
    </div>
    `
        : ""
    }
  </div>
</template>

<style lang="less">
#app {
  width: 100%;
  height: 100%;

  #development {
    height: 100%;
    box-sizing: border-box;
    overflow: hidden;
    display: flex;

    #main {
      height: 100%;
      position: relative;

      .expand-btn {
        width: 40px;
        height: 40px;
        position: absolute;
        z-index: 2000;
        top: 50%;
        right: 0;
        display: flex;
        transform: translate(50%, -50%);
        border-radius: 50%;

        svg {
          position: absolute;
          width: 30px;
          height: 30px;
        }
      }

      .el-carousel {
        width: 100%;
        height: 100%;

        .el-carousel__container {
          width: 100%;
          height: 100%;
        }

        .el-carousel__indicators {
          bottom: 120px;
          transform: translateX(-50%) scale(1.3);

          .el-carousel__indicator .el-carousel__button {
            background: gray;
          }

          .is-active .el-carousel__button {
            background: red;
          }
        }
      }
    }${
      hasDesignConfiguration
        ? `\n\n    #configuration {
      padding: 20px 10px 0 10px;
      height: 100%;
      background-color: #f0f2f5;
      width: 300px;
      box-sizing: border-box;
      overflow: auto;
    }  
      `
        : ""
    }
  }
}
</style>
`;
  fs.writeFileSync(
    path.resolve(__dirname, `./${basePath}/src/components/development/App.vue`),
    templateContent
  );
}

// 删除不需要的文件
function deleteExtraFiles(basePath, viewAnswer) {
  if (!viewAnswer.some(item => item.viewType === "designConfiguration")) {
    fse.removeSync(
      path.resolve(
        __dirname,
        `./${basePath}/src/components/designConfiguration`
      )
    );
  }
  if (viewAnswer.some(item => item.viewType === "main" && !item.process)) {
    fse.removeSync(
      path.resolve(
        __dirname,
        `./${basePath}/src/components/main/eventActionDesinitions.js`
      )
    );
  }
}

// 各视图
function generateNewFiles(basePath, viewAnswer) {
  const hasDesignConfiguration = viewAnswer.some(
    item => item.viewType === "designConfiguration"
  );
  viewAnswer.forEach(item => {
    let templateContent = "";
    if (item.viewType !== "designConfiguration") {
      templateContent = `<script setup>${
        item.process
          ? `\nimport useRegister from '@/hooks/useRegister';
import eventActionDefinitions from './eventActionDefinitions';`
          : ""
      }
const { ref, reactive, onMounted, useAttrs } = Vue3;

const props = defineProps({${
        hasDesignConfiguration ? `\n  customConfig: Object,` : ""
      }${item.process ? `\n  triggerEvent: Function,` : ""}
  componentId: String,
});
const attrs = useAttrs();
const newProps = reactive({ ...props, ...attrs });
${
  item.process
    ? `\nconst do_EventCenter_message = ({ value }) => {
  alert(value);
};

const actions = {
  do_EventCenter_message,
};

useRegister(newProps, actions, eventActionDefinitions);\n`
    : ""
}
const handleClick = () => {
  number.value++;${
    item.process
      ? `\n  newProps.triggerEvent?.('click', { value: number.value });`
      : ""
  }
};

const number = ref(0);

onMounted(() => {
  // eslint-disable-next-line no-unused-vars
  newProps.eventBus?.on(newP => {});${
    item.process ? `\n  newProps.triggerEvent?.("mounted")` : ""
  }
});
</script>

<template>
  {{ number }}
  <el-button @click="handleClick">点击</el-button>
</template>
`;
    } else {
      templateContent = `<script setup>
const { reactive, watch } = Vue3;

const props = defineProps({
  customConfig: Object,
  changeCustomConfig: Function,
});

const config = reactive(props.customConfig);

watch(config, () => props.changeCustomConfig?.(config));
</script>

<template>
  <el-form :model="config" :label-width="60">
    <el-form-item label="id" prop="id">
      <el-input v-model="config.id" />
    </el-form-item>
  </el-form>
</template>
`;
    }
    mkdirSync(
      path.resolve(__dirname, `./${basePath}/src/components/${item.viewType}`)
    );
    if (item.process) {
      fse.copySync(
        path.resolve(
          __dirname,
          `./vue/src/components/main/eventActionDefinitions.js`
        ),
        path.resolve(
          __dirname,
          `./${basePath}/src/components/${item.viewType}/eventActionDefinitions.js`
        )
      );
    }
    fs.writeFileSync(
      path.resolve(
        __dirname,
        `./${basePath}/src/components/${item.viewType}/App.vue`
      ),
      templateContent
    );
  });
}

// components/index.js
function handleComponentsIndexjs(basePath, viewAnswer) {
  const importStatement = viewAnswer
    .map(
      item =>
        `import ${toCamelCase(item.viewType)} from "./${
          item.viewType
        }/App.vue";`
    )
    .join("\n");
  const exportStatement = viewAnswer
    .map(item => toCamelCase(item.viewType))
    .join(",\n  ");
  let componentsIndexjs = `${importStatement}
import Development from "./development/App.vue";
import OnlineDevelopmentModeDetails from "./development/OnlineDevelopmentModeDetails.vue";
export {
  Development, 
  OnlineDevelopmentModeDetails,
  ${exportStatement}
};

`;
  fs.writeFileSync(
    path.resolve(__dirname, `./${basePath}/src/components/index.js`),
    componentsIndexjs
  );
}

// src/App.vue
function handleAppVue(basePath, viewAnswer) {
  const importStatement = viewAnswer
    .map(item => toCamelCase(item.viewType))
    .join(",\n  ");
  const renderMap = viewAnswer
    .map(item => `${item.viewType}: ${toCamelCase(item.viewType)}`)
    .join(",\n  ");
  const srcAppVue = `<script setup>
import {
  ${importStatement}
} from "./components";
import adapter from "./utils/handlePlatform/adapter";

const { onMounted, reactive, useAttrs } = Vue3;

const props = defineProps({
  type: String,
});
const attrs = useAttrs();
let newProps = reactive({ ...props, ...attrs });

const renderhMap = {
  ${renderMap}
};

onMounted(() => {
  newProps.eventBus?.on(newP => {
    newProps = adapter(newP);
  });
});
</script>

<template>
  <component :is="renderhMap[props.type || 'main']" v-bind="newProps" />
</template>
`;
  fs.writeFileSync(
    path.resolve(__dirname, `./${basePath}/src/App.vue`),
    srcAppVue
  );
}

// 创建文件夹
function mkdirSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    //如果父级目录已经创建，然后才能创建子级目录
    if (mkdirSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
}

// 将字符串首字母大写
function toCamelCase(str) {
  return `${str.slice(0, 1).toUpperCase()}${str.slice(1)}`;
}
